package yxy.game.pm2.bean.task;

import org.joda.time.DateTime;
import org.redisson.api.RMap;
import yxy.apple.logger.Logger;
import yxy.apple.util.BeanUtils;
import yxy.apple.util.RandomStringUtility;
import yxy.apple.util.redisson.RedisException;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.task;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.game.pm2.bean.Currency;
import yxy.game.pm2.bean.db.newDao.TaskDAO;
import yxy.game.pm2.bean.db.po.TaskPo;
import yxy.game.pm2.bean.module.BaseGameRedisLockBean;
import yxy.game.pm2.bean.module.rank.openserviceactive.RecordTaskFirstPlayrerBean;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Task extends BaseGameRedisLockBean {
	protected static Logger logger = Logger.create(Task.class);

	// bean===========================================================================
	private String playerCode;
	private String code;
	private int dataId;
	private long progress;
	private boolean finish;
	private boolean reward;
	private int extraParam;// 附加参数 扩展功能用

	public String getPlayerCode() {
		return playerCode;
	}

	public void setPlayerCode(String playerCode) {
		this.playerCode = playerCode;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public int getDataId() {
		return dataId;
	}

	public void setDataId(int dataId) {
		this.dataId = dataId;
	}

	public long getProgress() {
		return progress;
	}

	public void setProgress(long progress) {
		this.progress = progress;
	}

	public boolean isFinish() {
		return finish;
	}

	public void setFinish(boolean finish) {
		this.finish = finish;
	}

	public boolean isReward() {
		return reward;
	}

	public void setReward(boolean reward) {
		this.reward = reward;
	}

	public int getExtraParam() {
		return extraParam;
	}

	public void setExtraParam(int extraParam) {
		this.extraParam = extraParam;
	}

	// func==========================================================================

	public long progress() {
		return Math.abs(getProgress());
	}

	public void count(long value, long condition) {
		if (isFinish()) {
			return;
		}
		task data = DataCenter.getData(getDataId(), task.class);
		if (data == null) {
			return;
		}
		if (data.getFinishref()[1] >= 0 && condition != data.getFinishref()[1]) {
			return;
		}
		progress += value;
		if (progress >= data.getFinishref()[0]) {
			progress = data.getFinishref()[0];
			setFinish(true);
		}
		set();
	}

	/**
	 * 带记录功能
	 */
	public void countRecord(long value, long condition ,String playerCode,int acttype) {
		if (isFinish()) {
			return;
		}
		task data = DataCenter.getData(getDataId(), task.class);
		if (data == null) {
			return;
		}
		if (data.getFinishref()[1] >= 0 && condition != data.getFinishref()[1]) {
			return;
		}
		progress += value;
//		String name = Thread.currentThread().getName();
//		logger.info("当前线程：%s## 当前任务id：%s## 当前任务code：%s## 当前进度：%s",name,dataId,code,progress);
		if (progress >= data.getFinishref()[0]) {
			progress = data.getFinishref()[0];
			setFinish(true);
			//记录第一名完成该任务的 当前时间 玩家信息 任务id
			RecordTaskFirstPlayrerBean.record(DateTime.now(),playerCode,getDataId(),acttype);
		}
		set();
	}

	public void check(long value, long condition) {
		if (isFinish()) {
			return;
		}
		task data = DataCenter.getData(getDataId(), task.class);
		if (data == null) {
			return;
		}
		if (data.getFinishref()[1] >= 0 && condition != data.getFinishref()[1]) {
			return;
		}
		if (value < progress && progress != 0) {
			return;
		}
		progress = value;
		if (progress >= 0) {
			if (progress >= data.getFinishref()[0]) {
				progress = data.getFinishref()[0];
				setFinish(true);
			}
		} else {
			// 负值用于存储名次类趋小数值
			if (progress >= -data.getFinishref()[0]) {
				progress = -data.getFinishref()[0];
				setFinish(true);
			}
		}
		set();
	}

	/**
	 * 带记录功能
	 */
	public void checkRecord(long value, long condition ,String playerCode,int acttype) {
		if (isFinish()) {
			return;
		}
		task data = DataCenter.getData(getDataId(), task.class);
		if (data == null) {
			return;
		}
		if (data.getFinishref()[1] >= 0 && condition != data.getFinishref()[1]) {
			return;
		}
		if (value < progress && progress != 0) {
			return;
		}
		progress = value;
		if (progress >= 0) {
			if (progress >= data.getFinishref()[0]) {
				progress = data.getFinishref()[0];
				setFinish(true);
				//记录第一名完成该任务的 当前时间 玩家信息 任务id
				RecordTaskFirstPlayrerBean.record(DateTime.now(),playerCode,getDataId(),acttype);
			}
		} else {
			// 负值用于存储名次类趋小数值
			if (progress >= -data.getFinishref()[0]) {
				progress = -data.getFinishref()[0];
				setFinish(true);
				//记录第一名完成该任务的 当前时间 玩家信息 任务id
				RecordTaskFirstPlayrerBean.record(DateTime.now(),playerCode,getDataId(),acttype);
			}
		}
		set();
	}

	public void clear2() {
		try {
			if (lockTask(playerCode)) {
				setProgress(0);
				setFinish(false);
				setReward(false);
				set();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			unlockTask(playerCode);
		}
	}

	public Collection<Currency> reward() {
		task data = DataCenter.getData(getDataId(), task.class);
		return Currency.create(data.getRewardtype(), data.getRewardid(), data.getRewardnum());
	}

	// redis==========================================================================

	private static String key(String playerCode) {
		return String.format("PLAYER:%s:TASK", playerCode);
	}

	static private RMap<String, Task> touch(String playerCode) throws RedisException {
		RMap<String, Task> map = getMapFromRedis(playerCode);
		if (!map.isExists()) {//redis没数据就从数据库取数据
			List<TaskPo> all = TaskDAO.getList(playerCode);
			if (all.size() > 0) {
				Map<String, Task> collect = all.stream().collect(Collectors.toMap(TaskPo::getCode, e -> BeanUtils.map(e, Task.class), (a, b) -> b, HashMap::new));
				map.putAll(collect);
			}
		}
		return map;
	}

	static private RMap<String, Task> getMapFromRedis(String playerCode) throws RedisException {
		return RedisManager.client(redis()).getMap(key(playerCode));
	}

	static public void saveToDB(String playerCode) {
		try {
			long updateTime = System.currentTimeMillis();//时间戳

			RMap<String, Task> map = touch(playerCode);
			if (map.isExists()) {
				int count = 0;
				if (map.size() > 0) {
					List<TaskPo> collect = map.values().stream().map(e -> BeanUtils.map(e, TaskPo.class)).collect(Collectors.toList());
					TaskDAO.replace(playerCode, collect, updateTime);
					count++;
				}

				if(count > 0) {//二次确认数据已经入库后，进行删除操作
					TaskDAO.delete(playerCode, updateTime);
				}
			}
		}catch (Exception e){
			e.printStackTrace();
		}

	}

	static public Task create(String playerCode, task data, int extra) {
		try {
			TaskType type = TaskType.forNumber(data.getFinish());
			String code = randomTaskCode(type);
			RMap<String, Task> tasks = touch(playerCode);
			while (tasks.containsKey(code)) {
				code = randomTaskCode(type);
			}

			Task task = new Task();
			task.setPlayerCode(playerCode);
			task.setCode(code);
			task.setDataId(data.getId());
			task.setExtraParam(extra);
			task.set();
			return task;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	static public Task create(String playerCode, task data) {
		return create(playerCode, data, 0);
	}

	static public Map<String, Task> all(String playerCode) {
		try {
			return touch(playerCode).readAllMap();
		} catch (RedisException e) {
		}
		return new HashMap<>();
	}

	static public Task get(String playerCode, String code) {
		try {
			Task task = touch(playerCode).get(code);
			return task;
		} catch (Exception e) {
			return null;
		}
	}

	static public Map<String, Task> getByType(String playerCode, TaskType type) {
		Map<String, Task> result = new HashMap<>();
		int typeNumber = type.getNumber();
		Map<String, Task> tasks = all(playerCode);
		for (Task task : tasks.values()) {
			if (task.getCode().startsWith(String.format("%s_tt", typeNumber))) {
				result.put(task.getCode(), task);
			}
		}
		return result;
	}

	public void set() {
		try {
			touch(getPlayerCode()).put(getCode(), this);
		} catch (RedisException e) {
			e.printStackTrace();
		}
	}

	static private String randomTaskCode(TaskType type) {
		return String.format("%s_tt%s", type.getNumber(), RandomStringUtility.randomLowerNumeric(4));
	}

	public static void remove(String playerCode, String taskCode) {
		try {
			touch(playerCode).remove(taskCode);
		} catch (RedisException e) {
			e.printStackTrace();
		}
	}

	public static void remove(String playerCode, Collection<String> taskCodes) {
		try {
			RMap<String, Task> tasks = touch(playerCode);
			for (String taskCode : taskCodes) {
				tasks.remove(taskCode);
			}
		} catch (RedisException e) {
			e.printStackTrace();
		}
	}

	public static void removeAllFromRedis(String playerCode) throws RedisException {
		getMapFromRedis(playerCode).delete();
	}

	// lock==========================================================================

	static private String lockKey(String playerCode) {
		return String.format("lock:%s", key(playerCode));
	}

	static public boolean lockTask(String playerCode) throws InterruptedException {
		return tryLock(lockKey(playerCode));
	}

	static public void unlockTask(String playerCode) {
		unlock(lockKey(playerCode));
	}

}
